package com.groupYLP.CouponNexus.merchant.admin.dao.sharding;

import lombok.Getter;
import org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.apache.shardingsphere.sharding.exception.algorithm.sharding.ShardingAlgorithmInitializationException;

import java.util.Collection;
import java.util.List;
import java.util.Properties;

/**
 * 基于HashMod方式自定义分库算法
 */
public final class DBHashModShardingAlgorithm implements StandardShardingAlgorithm<Long> {

    // 使用Getter注解，自动生成属性props的getter方法
    @Getter
    private Properties props;

    // 分片总数
    private int shardingCount;
    // 分片数量的配置键
    private static final String SHARDING_COUNT_KEY = "sharding-count";

    /**
     * 执行精确分片
     *
     * @param availableTargetNames 可用的数据节点名称集合
     * @param shardingValue 分片值
     * @return 选择的数据节点名称
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        long id = shardingValue.getValue();
        int dbSize = availableTargetNames.size();
        // 计算哈希分片值，并取模决定数据节点
        int mod = (int) hashShardingValue(id) % shardingCount / (shardingCount / dbSize);
        int index = 0;
        // 遍历数据节点，找到匹配的节点
        for (String targetName : availableTargetNames) {
            if (index == mod) {
                return targetName;
            }
            index++;
        }
        // 如果没有找到匹配的节点，抛出异常
        throw new IllegalArgumentException("No target found for value: " + id);
    }

    /**
     * 执行范围分片
     *
     * @param availableTargetNames 可用的数据节点名称集合
     * @param shardingValue 分片值范围
     * @return 选择的数据节点名称集合
     */
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        // 暂无范围分片场景，默认返回空
        return List.of();
    }

    /**
     * 初始化分片算法
     *
     * @param props 分片算法配置属性
     */
    @Override
    public void init(Properties props) {
        this.props = props;
        // 从配置属性中获取分片总数
        shardingCount = getShardingCount(props);
    }

    /**
     * 从属性中获取分片总数
     *
     * @param props 分片算法配置属性
     * @return 分片总数
     */
    private int getShardingCount(final Properties props) {
        // 确保分片总数配置存在，否则抛出异常
        ShardingSpherePreconditions.checkState(props.containsKey(SHARDING_COUNT_KEY), () -> new ShardingAlgorithmInitializationException(getType(), "Sharding count cannot be null."));
        return Integer.parseInt(props.getProperty(SHARDING_COUNT_KEY));
    }

    /**
     * 计算分片值的哈希值
     *
     * @param shardingValue 分片值
     * @return 哈希值
     */
    private long hashShardingValue(final Comparable<?> shardingValue) {
        // 使用绝对值确保哈希值为正数
        return Math.abs((long) shardingValue.hashCode());
    }

}
